package xencrypt

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"fmt"
	"os"
)

//读取RSA私钥
func GetRSAPrivateKey(path string) *rsa.PrivateKey {
	//读取文件内容
	file, err := os.Open(path)
	if err != nil {
		panic(fmt.Sprintf("读取RSA私钥错误：%s", err.Error()))
	}
	defer file.Close()
	info, _ := file.Stat()
	buf := make([]byte, info.Size())
	file.Read(buf)
	//pem解码
	block, _ := pem.Decode(buf)
	//X509解码
	prkI, err := x509.ParsePKCS8PrivateKey(block.Bytes)

	privateKey := prkI.(*rsa.PrivateKey)
	return privateKey
}

//读取RSA公钥
func GetRSAPublicKey(path string) *rsa.PublicKey {
	//读取公钥内容
	file, err := os.Open(path)
	if err != nil {
		panic(fmt.Sprintf("读取RSA公钥错误：%s", err.Error()))
	}
	defer file.Close()
	info, _ := file.Stat()
	buf := make([]byte, info.Size())
	file.Read(buf)
	//pem解码
	block, _ := pem.Decode(buf)
	//x509解码
	publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		panic(err)
	}
	publicKey := publicKeyInterface.(*rsa.PublicKey)
	return publicKey
}

func EncodeRSA(msg string, publicKeyPath string) string {
	pub := GetRSAPublicKey(publicKeyPath)
	encode, _ := rsa.EncryptPKCS1v15(rand.Reader, pub, []byte(msg))
	encodeString := base64.StdEncoding.EncodeToString(encode)
	return encodeString
}

func DecodeRSA(msg string, privateKeyPath string) string {
	decodeByte, _ := base64.StdEncoding.DecodeString(msg)
	private := GetRSAPrivateKey(privateKeyPath)

	decode, _ := rsa.DecryptPKCS1v15(rand.Reader, private, decodeByte)
	encodeString := string(decode)
	return encodeString
}

//对消息的散列值进行数字签名
func GetSign(msg []byte, path string) string {
	//取得私钥
	privateKey := GetRSAPrivateKey(path)
	//计算散列值
	hash := crypto.Hash.New(crypto.SHA1)
	hash.Write(msg)
	bytes := hash.Sum(nil)
	//SignPKCS1v15使用RSA PKCS#1 v1.5规定的RSASSA-PKCS1-V1_5-SIGN签名方案计算签名
	signByte, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA1, bytes)
	if err != nil {
		panic(signByte)
	}
	sign := base64.StdEncoding.EncodeToString(signByte)

	return sign
}

//验证数字签名
func VerifyRSASign(msg string, sign string, publicKeyPath string) bool {
	//取得公钥
	publicKey := GetRSAPublicKey(publicKeyPath)
	//计算消息散列值
	hash := crypto.Hash.New(crypto.SHA1)
	hash.Write([]byte(msg))
	bytes := hash.Sum(nil)
	//验证数字签名
	newSign, _ := base64.StdEncoding.DecodeString(sign)
	err := rsa.VerifyPKCS1v15(publicKey, crypto.SHA1, bytes, newSign)
	return err == nil
}
